{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "cb354baf",
   "metadata": {},
   "source": [
    "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langchain-ai/langchain-academy/blob/main/module-1/router.ipynb) [![Open in LangChain Academy](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66e9eba12c7b7688aa3dbb5e_LCA-badge-green.svg)](https://academy.langchain.com/courses/take/intro-to-langgraph/lessons/58239412-lesson-5-router)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "ce6fff79-25b5-4884-8aaa-e3ebb7ddd549",
   "metadata": {},
   "source": [
    "# Router\n",
    "\n",
    "## Review\n",
    "\n",
    "We built a graph that uses `messages` as state and a chat model with bound tools.\n",
    "\n",
    "We saw that the graph can:\n",
    "\n",
    "* Return a tool call\n",
    "* Return a natural language response\n",
    "\n",
    "## Goals\n",
    "\n",
    "We can think of this as a router, where the chat model routes between a direct response or a tool call based upon the user input.\n",
    "\n",
    "This is an simple example of an agent, where the LLM is directing the control flow either by calling a tool or just responding directly. \n",
    "\n",
    "![Screenshot 2024-08-21 at 9.24.09 AM.png](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66dbac6543c3d4df239a4ed1_router1.png)\n",
    "\n",
    "Let's extend our graph to work with either output! \n",
    "\n",
    "For this, we can use two ideas:\n",
    "\n",
    "(1) Add a node that will call our tool.\n",
    "\n",
    "(2) Add a conditional edge that will look at the chat model model output, and route to our tool calling node or simply end if no tool call is performed. \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ebb4fc6e-7c85-4fc8-a4a9-0c7a527c4e5b",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%capture --no-stderr\n",
    "%pip install --quiet -U langchain_openai langchain_core langgraph"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "885e92d9",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os, getpass\n",
    "\n",
    "def _set_env(var: str):\n",
    "    if not os.environ.get(var):\n",
    "        os.environ[var] = getpass.getpass(f\"{var}: \")\n",
    "\n",
    "_set_env(\"OPENAI_API_KEY\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "e3ba4df4-3045-49b1-9299-ced1fce14d24",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "def multiply(a: int, b: int) -> int:\n",
    "    \"\"\"Multiply a and b.\n",
    "\n",
    "    Args:\n",
    "        a: first int\n",
    "        b: second int\n",
    "    \"\"\"\n",
    "    return a * b\n",
    "\n",
    "llm = ChatOpenAI(model=\"gpt-4o\")\n",
    "llm_with_tools = llm.bind_tools([multiply])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c77555a2",
   "metadata": {},
   "source": [
    " We use the [built-in `ToolNode`](https://langchain-ai.github.io/langgraph/reference/prebuilt/?h=tools+condition#toolnode) and simply pass a list of our tools to initialize it. \n",
    " \n",
    " We use the [built-in `tools_condition`](https://langchain-ai.github.io/langgraph/reference/prebuilt/?h=tools+condition#tools_condition) as our conditional edge."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "9a6fde4e-cceb-4426-b770-97ee4b41e9da",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/jpeg": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import Image, display\n",
    "from langgraph.graph import StateGraph, START, END\n",
    "from langgraph.graph import MessagesState\n",
    "from langgraph.prebuilt import ToolNode\n",
    "from langgraph.prebuilt import tools_condition\n",
    "\n",
    "# Node\n",
    "def tool_calling_llm(state: MessagesState):\n",
    "    return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n",
    "\n",
    "# Build graph\n",
    "builder = StateGraph(MessagesState)\n",
    "builder.add_node(\"tool_calling_llm\", tool_calling_llm)\n",
    "builder.add_node(\"tools\", ToolNode([multiply]))\n",
    "builder.add_edge(START, \"tool_calling_llm\")\n",
    "builder.add_conditional_edges(\n",
    "    \"tool_calling_llm\",\n",
    "    # If the latest message (result) from assistant is a tool call -> tools_condition routes to tools\n",
    "    # If the latest message (result) from assistant is a not a tool call -> tools_condition routes to END\n",
    "    tools_condition,\n",
    ")\n",
    "builder.add_edge(\"tools\", END)\n",
    "graph = builder.compile()\n",
    "\n",
    "# View\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "11b608c5-0c15-4fb7-aa24-80ce5774fb85",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "Hello world.\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "Hello! How can I assist you today?\n"
     ]
    }
   ],
   "source": [
    "from langchain_core.messages import HumanMessage\n",
    "messages = [HumanMessage(content=\"Hello world.\")]\n",
    "messages = graph.invoke({\"messages\": messages})\n",
    "for m in messages['messages']:\n",
    "    m.pretty_print()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "34708377-16b6-4474-9e23-71890c1fb36e",
   "metadata": {},
   "source": [
    "Now, we can see that the graph runs the tool!\n",
    "\n",
    "It responds with a `ToolMessage`. \n",
    "\n",
    "## LangGraph Studio\n",
    "\n",
    "--\n",
    "\n",
    "**⚠️ DISCLAIMER**\n",
    "\n",
    "*Running Studio currently requires a Mac. If you are not using a Mac, then skip this step.*\n",
    "\n",
    "--\n",
    "\n",
    "Load the `router` in Studio, which uses `module-1/studio/router.py` set in `module-1/studio/langgraph.json`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "43782c33-0f41-47f2-ae38-ddb2cd4ba6f8",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
